package cn.hicard.risk.task;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import cn.hicard.risk.common.Constant;
import cn.hicard.risk.entity.BdCallorder;
import cn.hicard.util.AppConfig;

/**
 * 同步金掌柜调单数据状态到汇卡网用的线程
 * @author zhangy
 *
 */
public class JzgSyncRunnable implements Runnable{
	
	/** 使用一个线程安全的队列保存将要处理的数据 */
	private static ConcurrentLinkedQueue<List<BdCallorder>> queue = new ConcurrentLinkedQueue<List<BdCallorder>>();
	
	private static Logger logger = Logger.getLogger(Constant.LOGGER_MAIN);
	
	/** 标记是否已实例化 */
	private static boolean instanceFlag = false;
	
	/** 构造方法 */
	public JzgSyncRunnable(){
		instanceFlag = true;
	}
		
	/**
	 * 将批量要发送的金掌柜调单数据放入队列中
	 * @param callorders
	 */
	public static void offerToQueue(List<BdCallorder> callorders){
		// 以免生NullPointerException等类型不可预测的异常导致线程坏死
		if(instanceFlag){
			try {
				queue.offer(callorders);
			} catch (Exception e) {
				logger.error("",e);
			}			
		}else{
			logger.warn("本Runable未被线程调度，不接受传入的数据");
		}
	}

	@Override
	public void run() {
		
		// 调单数据处理结果所要发送到的地址URL
		String sendurl = AppConfig.get("callorder_sendurl");
		// 传送字符数据时所使用的编码
		String charset = AppConfig.get("callorder_charset");
		// 每批数据的处理时间间隔
		long sleepTime = Long.valueOf(AppConfig.get("callorder_sync_timespan"));

		while(true){
			
			List<BdCallorder> callorders = queue.poll();
			
			if(callorders != null && callorders.size() > 0){
				// 拿出这批数据的主键，用以记录日志
				StringBuffer sbid = new StringBuffer();
				for (BdCallorder callorder : callorders) {
					sbid.append(callorder.getPkCallorder());
					sbid.append(",");
				}
				sbid.deleteCharAt(sbid.length()-1);
				
				logger.debug("批量发送调单处理结果开始，将要处理的调单数据量"+callorders.size());
				String xml = createXml(callorders, charset);
				
				logger.info("准备发住汇卡网-金掌柜管理系统的XML内容为：" + xml);
				String code = sendCallorderXml(xml, sendurl, charset);
				
				logger.info("该批金掌柜调单数据主键集合为[" + sbid.toString()+"]的已经处理完成,返回结果" + code);
			} else {
				try {
					Thread.sleep(sleepTime);
				} catch (Exception e) {
				}
			}
			logger.debug("线程任务执行一次,待处理的队列中还有数据量" + queue.size());
		}		
		
	}
	
	private String sendCallorderXml(String xml, String sendurl, String charset){		
		// 最终要返回发送结果
		String sendResult = "00";
		
		HttpClient client = new DefaultHttpClient();
		// 以POS方式传输大量的数据
		HttpPost post =  new HttpPost(sendurl);
		// 使用约定好的byte数据流传输数据，避免各平台字符编码乱码
		HttpEntity entity = new ByteArrayEntity(xml.getBytes(Charset.forName(charset)));
		post.setEntity(entity);
		
		// 如果出错，则共尝试发送3次
		BufferedReader reader = null;
		for(int i=1; i<=3; i++){
			try {
				HttpResponse response = client.execute(post);
				reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
				String line = reader.readLine();
				if(line != null)sendResult = line.trim();
				break;
			} catch (Exception e) {
				logger.error("第" + i + "次发送XML出错:", e);
			} finally {				
					try {
						if(reader != null) reader.close();
					} catch (IOException e) {}
			}
		}	
		return sendResult;
	}
	
	/**
	 * 组装将要请求用的XML字符串
	 * @param callorders
	 * @param encoding
	 * @return
	 */
	private String createXml(List<BdCallorder> callorders, String encoding){
		// 注意：每个List中的数据为同一批数据，它们的处理的日期、处理人、审核结果、原因全部相同
		BdCallorder firstCalloder = callorders.get(0);
		
		// 组装XML
		Document xmldoc = DocumentHelper.createDocument();
		xmldoc.setXMLEncoding(encoding);
		Element root = xmldoc.addElement("result");
		
		// 被批量处理的ID集合
		Element ids = root.addElement("ids");
		for (BdCallorder callorder : callorders) {
			ids.addElement("id").setText(callorder.getOrderno());
		}
		
		// 处理的日期时间
		root.addElement("procdate").setText(firstCalloder.getProcdate());
		// 处理人
		root.addElement("procuser").setText(firstCalloder.getProcuser());
		// 审核状态
		root.addElement("state").setText(firstCalloder.getCheckstate());
		// 原因
		root.addElement("reason").setText(firstCalloder.getReason());

		// 最终的结果XML
		return xmldoc.asXML();		
	}

}
